/**
 * 石头、剪刀、布游戏 - 进程间通信(IPC)模板
 *
 * 本模板提供石头剪刀布游戏的基本框架，学生需要实现不同的IPC机制
 * 可以实现的IPC机制包括：管道、消息队列、共享内存、套接字等
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
/* TODO 1: 根据你选择的IPC机制，添加必要的头文件 */
/* 例如：
 * #include <sys/ipc.h>   // 对于System V IPC（消息队列、共享内存、信号量）
 * #include <sys/msg.h>   // 对于消息队列
 * #include <sys/shm.h>   // 对于共享内存
 * #include <sys/sem.h>   // 对于信号量
 * #include <sys/socket.h> // 对于套接字
 * #include <netinet/in.h> // 对于网络套接字
 */

/* 游戏相关常量定义 */
#define MAX_ROUNDS 120  // 最大回合数
#define BUFFER_SIZE 256 // 缓冲区大小

/* 手势定义 */
#define ROCK '0'     // 石头
#define SCISSORS '1' // 剪刀
#define PAPER '2'    // 布

/* 比赛结果定义 */
#define PLAYER_A_WIN 1  // 玩家A获胜
#define DRAW 0          // 平局
#define PLAYER_B_WIN -1 // 玩家B获胜

/* TODO 2: 声明你需要的全局变量，用于IPC通信 */
/* 例如：
 * 对于管道: int pipe_a[2], pipe_b[2];
 * 对于消息队列: int msgq_id;
 * 对于共享内存: int shm_id; void* shm_ptr;
 * 对于套接字: int server_fd, client_fd;
 */

/**
 * 判断一轮比赛的胜负
 *
 * @param move_a 玩家A的选择
 * @param move_b 玩家B的选择
 * @return 比赛结果
 */
int judge(char move_a, char move_b)
{
    if (move_a == move_b)
        return DRAW;

    if ((move_a == ROCK && move_b == SCISSORS) ||
        (move_a == SCISSORS && move_b == PAPER) ||
        (move_a == PAPER && move_b == ROCK))
        return PLAYER_A_WIN;
    else
        return PLAYER_B_WIN;
}

/**
 * 将数字手势转换为可读的字符串
 */
const char *move_to_string(char move)
{
    switch (move)
    {
    case ROCK:
        return "石头";
    case SCISSORS:
        return "剪刀";
    case PAPER:
        return "布";
    default:
        return "未知";
    }
}

/**
 * TODO 3: 初始化IPC资源
 *
 * 根据你选择的IPC机制，初始化必要的资源
 *
 * @return 0表示成功，-1表示失败
 */
int init_ipc()
{
    /*
     * 在这里实现IPC资源的初始化
     * 例如：创建管道、消息队列、共享内存、套接字等
     */

    return 0; // 成功返回0
}

/**
 * TODO 4: 清理IPC资源
 *
 * 在程序结束时清理所有IPC资源
 *
 * @return 0表示成功，-1表示失败
 */
int cleanup_ipc()
{
    /*
     * 在这里实现IPC资源的清理
     * 例如：关闭管道、删除消息队列、分离和删除共享内存、关闭套接字等
     */

    return 0; // 成功返回0
}

/**
 * TODO 5: 玩家A进程函数
 *
 * 玩家A需要生成手势并通过IPC发送给裁判进程
 *
 * @param rounds 比赛回合数
 */
void player_a_process(int rounds)
{
    /* 设置随机数种子 */
    srand(time(NULL) + getpid());

    /*
     * 在这里实现玩家A的逻辑：
     * 1. 准备IPC通信（关闭不需要的文件描述符等）
     * 2. 生成rounds轮的随机手势
     * 3. 通过IPC机制发送给裁判进程
     */

    exit(EXIT_SUCCESS); // 玩家A进程结束
}

/**
 * TODO 6: 玩家B进程函数
 *
 * 玩家B需要生成手势并通过IPC发送给裁判进程
 *
 * @param rounds 比赛回合数
 */
void player_b_process(int rounds)
{
    /* 设置不同的随机数种子 */
    srand(time(NULL) + getpid() + 100);

    /*
     * 在这里实现玩家B的逻辑：
     * 1. 准备IPC通信（关闭不需要的文件描述符等）
     * 2. 生成rounds轮的随机手势
     * 3. 通过IPC机制发送给裁判进程
     */

    exit(EXIT_SUCCESS); // 玩家B进程结束
}

/**
 * TODO 7: 从玩家A接收一轮手势
 *
 * @param move_a 用于存储接收到的手势
 * @return 0表示成功，-1表示失败
 */
int receive_from_player_a(char *move_a)
{
    /*
     * 在这里实现从玩家A接收手势的代码
     * 根据你选择的IPC机制进行实现
     */

    return 0; // 成功返回0
}

/**
 * TODO 8: 从玩家B接收一轮手势
 *
 * @param move_b 用于存储接收到的手势
 * @return 0表示成功，-1表示失败
 */
int receive_from_player_b(char *move_b)
{
    /*
     * 在这里实现从玩家B接收手势的代码
     * 根据你选择的IPC机制进行实现
     */

    return 0; // 成功返回0
}

/**
 * 主函数 - 裁判进程逻辑
 */
int main()
{
    int rounds;         // 比赛回合数
    pid_t pid_a, pid_b; // 玩家进程ID
    int player_a_wins = 0;     // 玩家A获胜次数
    int player_b_wins = 0;     // 玩家B获胜次数
    int draws = 0;      // 平局次数

    /* 初始化IPC资源 */
    if (init_ipc() != 0)
    {
        fprintf(stderr, "初始化IPC资源失败\n");
        exit(EXIT_FAILURE);
    }

    /* 获取用户输入的比赛回合数 */
    printf("请输入比赛回合数 (最大 %d): ", MAX_ROUNDS);
    scanf("%d", &rounds);

    /* 验证回合数的有效性 */
    if (rounds <= 0 || rounds > MAX_ROUNDS)
    {
        printf("回合数无效，使用默认值: 10\n");
        rounds = 10;
    }

    /* 创建玩家A进程 */
    if ((pid_a = fork()) < 0)
    {
        perror("创建玩家A进程失败");
        cleanup_ipc();
        exit(EXIT_FAILURE);
    }
    else if (pid_a == 0)
    {
        /* 玩家A进程 */
        player_a_process(rounds);
        /* 不会执行到这里 */
    }

    /* 创建玩家B进程 */
    if ((pid_b = fork()) < 0)
    {
        perror("创建玩家B进程失败");
        cleanup_ipc();
        exit(EXIT_FAILURE);
    }
    else if (pid_b == 0)
    {
        /* 玩家B进程 */
        player_b_process(rounds);
        /* 不会执行到这里 */
    }

    /* 裁判逻辑开始 */
    printf("\n===== 比赛开始，共%d回合 =====\n\n", rounds);

    /* 循环进行每一轮比赛 */
    for (int i = 0; i < rounds; i++)
    {
        char move_a, move_b;

        /* 接收玩家A的手势 */
        if (receive_from_player_a(&move_a) != 0)
        {
            fprintf(stderr, "从玩家A接收数据失败\n");
            break;
        }

        /* 接收玩家B的手势 */
        if (receive_from_player_b(&move_b) != 0)
        {
            fprintf(stderr, "从玩家B接收数据失败\n");
            break;
        }

        /* 判定胜负 */
        int result = judge(move_a, move_b);

        /* 更新统计 */
        switch (result)
        {
        case PLAYER_A_WIN:
            player_a_wins++;
            break;
        case DRAW:
            draws++;
            break;
        case PLAYER_B_WIN:
            player_b_wins++;
            break;
        }

        /* 显示当前回合结果 */
        printf("-----------------------------\n");
        printf("第 %d 回合对决:\n", i + 1);
        printf("玩家A: %s\n", move_to_string(move_a));
        printf("玩家B: %s\n", move_to_string(move_b));
        printf("结果: ");

        switch (result)
        {
        case PLAYER_A_WIN:
            printf("玩家A获胜!\n");
            break;
        case DRAW:
            printf("平局!\n");
            break;
        case PLAYER_B_WIN:
            printf("玩家B获胜!\n");
            break;
        }
        printf("当前比分 - A:%d B:%d 平:%d\n", player_a_wins, player_b_wins, draws);
    }

    /* 等待子进程结束 */
    waitpid(pid_a, NULL, 0);
    waitpid(pid_b, NULL, 0);

    /* 清理IPC资源 */
    cleanup_ipc();

    /* 显示最终结果 */
    printf("\n===== 最终结果 =====\n");
    printf("总回合数: %d\n", rounds);
    printf("玩家A获胜: %d 轮\n", player_a_wins);
    printf("玩家B获胜: %d 轮\n", player_b_wins);
    printf("平局: %d 轮\n", draws);

    if (player_a_wins > player_b_wins)
    {
        printf("玩家A是最终赢家!\n");
    }
    else if (player_b_wins > player_a_wins)
    {
        printf("玩家B是最终赢家!\n");
    }
    else
    {
        printf("比赛最终打成平局!\n");
    }

    return 0;
}